/*
 * $Id$
 */

package corejs.rt;


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author pengyu
 */
public class RuntimeStack implements NameResolver<String, Value> {
  
   private List<ActivationRecord> _activationRecords;      
   private int _current;
   
   public RuntimeStack() {
      _activationRecords = new ArrayList<ActivationRecord>();
      _activationRecords.add(
         new ActivationRecord(new HashMap<String, Value>() {{
            put("this", JsObjects.createGlobalObject());
         }})
      );
      _current = 0;
   }
   
   /**
    *
    * @param name
    * @return
    */
   @Override
   public Value resolve(final String name) {
      return currentScope().resolve(name);
   }
   
   /**
    * 
    * @param name
    * @return 
    */
   public <T> T resolve(final String name, final Class<T> clz) {
      return resolve(name).cast(clz);
   }

   /**
    *
    * @param name
    * @param val
    * @return
    */
   @Override
   public Value store(final String name, final Value val) {
      if (currentScope().containsKey(name)) {
         currentScope().put(name, val);
      }
      else {
         storeGlobally(name, val);
      }
      return val;
   }


   public Value storeLocally(final String name, final Value val) {
      final ActivationRecord ar = currentScope();
      if (ar.hasParent()) {
         ar.put(name, val);
      }
      else {
         storeGlobally(name, val);
      }
      return val;
   }
   
   /**
    * 
    * @param name
    * @param obj
    * @return 
    */
   public Value storeGlobally(final String name, final Value obj) {
     return _activationRecords.get(0).get("this").store(name, obj);
   }
   
   /**
    *
    * @return
    */
   public RuntimeStack newScope() {
     return newScope(Collections.<String, Value>emptyMap());
   }
   
   /**
    *
    * @param init
    * @return
    */
   public RuntimeStack newScope(final Map<String, Value> init) {
     return newScope(currentScope(), init);
   }

   /**
    *
    * @param parent
    * @return
    */
   public RuntimeStack newScope(final ActivationRecord parent) {
      return newScope(parent, Collections.<String, Value>emptyMap());
   }

   /**
    *
    * @param parent
    * @param init
    * @return
    */
   public RuntimeStack newScope(final ActivationRecord parent, 
                                final Map<String, Value> init) {
      _activationRecords.add(new ActivationRecord(parent, init));
      ++_current;
      return this;
   }

   public Value popScope() {
      if (-1 == _current) {
         throw new IllegalStateException("-1");
      }
      return _activationRecords.remove(_current--).getReturn();
   }
   
   public ActivationRecord currentScope() {
      return _activationRecords.get(_current);
   }
   
   public Value getGlobalObject() {
      return _activationRecords.get(0).get("this");
   }
 
}
